package com.xtaller.easy.admin.config.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.xtaller.common.bean.CacheInfo;
import com.xtaller.common.bean.JWTResult;
import com.xtaller.common.convert.J;
import com.xtaller.common.convert.V;
import com.xtaller.common.kit.JwtKit;
import com.xtaller.easy.admin.base.BaseInterceptor;
import com.xtaller.easy.admin.config.R;
import com.xtaller.easy.admin.model.BaseUser;
import com.xtaller.easy.admin.service.impl.BaseUserService;
import com.xtaller.easy.admin.tps.CacheKit;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Taller on 2018/3/18
 * 第二层
 * token认证拦截
 *
 */
@Component
@Order(2)
public class AuthInterceptor extends BaseInterceptor {
    @Autowired
    private CacheKit cacheKit;
    @Autowired
    private BaseUserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o)
            throws IOException {
        HandlerMethod handlerMethod = (HandlerMethod) o;
        String token = request.getHeader("token");
        response.setHeader("Content-type", "text/html;charset=UTF-8");
        String className = getClassName(handlerMethod);
        int method = formatMethod(request.getMethod());
        if(V.isEmpty(token)){
            response.setStatus(401);
            response.getWriter().write(J.s2r("token 口令不能为空 !"));
            return false;
        }else{
            JWTResult jwt = JwtKit.validateJWT(token);
            if (jwt.isSuccess()) {
                Claims claims = jwt.getClaims();
                BaseUser user = userService.selectById(claims.getId());
                if(user == null) {
                    response.setStatus(403);
                    response.getWriter().write(J.s2r("签名用户数据异常", 1));
                    return false;
                }
                // 缓存检查
                CacheInfo info = cacheKit.getCacheInfo(user.getId());
                if(info == null) {
                    response.setStatus(403);
                    response.getWriter().write(J.s2r("缓存信息丢失请重新登录", 1));
                    return false;
                }

                if(className.indexOf("LogApi.getCount") >= 0
                        || className.indexOf("DictApi.getDictByCode") >= 0
                        || className.indexOf("ModuleApi.getModule") >= 0
                        || className.indexOf("RoleApi.getRole") >= 0
                        || className.indexOf("LogApi.getLog") >= 0
                        || className.indexOf("DictApi.getModule") >= 0
                        || className.indexOf("UserApi.loginOut") >= 0
                        || className.indexOf("UserApi.myPassword") >= 0){

                    return true;
                }else{
                    JSONObject data = J.o2j(info.getData());
                    List<JSONObject> auths = formatAuth(J.o2l(data.get("auth")));
                    List<JSONObject> btns = J.o2l(data.get("btns"));
                    List<JSONObject> apis = formatApi(auths, btns);
                    if(apis.size() == 0){
                        response.setStatus(403);
                        response.getWriter().write(J.s2r("您没有权限执行这个操作"));
                        return false;
                    }else{
                        boolean check = false;
                        for(JSONObject api:apis){
                           if(api.getInteger("method") == method &&
                                   api.getString("api").indexOf(className) >= 0){
                               check = true;
                               break;
                           }
                        }
                        if(!check){
                           response.setStatus(403);
                           response.getWriter().write(J.s2r("您没有权限执行这个操作"));
                           return false;
                        }
                    }
                    return true;
                }
            } else {
                switch (jwt.getErrCode()) {
                    // 签名验证不通过
                    case 4002:
                        response.setStatus(403);
                        response.getWriter().write(J.s2r("签名验证不通过", 1));
                        break;
                    // 签名过期
                    case 4001:
                        response.setStatus(403);
                        response.getWriter().write(J.s2r("签名过期", 1));
                        break;
                    default:
                        break;
                }
                return false;
            }
        }
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }

    private List<JSONObject> formatAuth(List<JSONObject> auths){
        List<JSONObject> list = new ArrayList<>();
        if(auths.size() > 0){
            for(JSONObject auth:auths){
                List<JSONObject> childrens = J.o2l(auth.get("children"));
                if(childrens.size() > 0){
                    for(JSONObject children:childrens){
                        list.add(children);
                    }
                }
            }
        }
        return list;
    }
    private List<JSONObject> formatApi(List<JSONObject> menus, List<JSONObject> btns){
        List<JSONObject> apis = new ArrayList<>();
        if(menus.size() > 0){
            for(JSONObject menu:menus){
                JSONObject tem = new JSONObject();
                tem.put("api", menu.getString("api"));
                tem.put("method", 1);
                apis.add(tem);
            }
        }
        if(btns.size() > 0){
            for(JSONObject btn:btns){
                List<JSONObject> items = J.o2l(btn.get("btns"));
                if(items.size() > 0){
                    for(JSONObject item:items){
                        JSONObject tem = new JSONObject();
                        tem.put("api", item.getString("api"));
                        tem.put("method", item.getInteger("method"));
                        apis.add(tem);
                    }
                }
            }
        }
        return apis;
    }
    private int formatMethod(String method){
        int code = 1;
        if(method.toLowerCase().equals("get")){
            code = 1;
        }
        if(method.toLowerCase().equals("post")){
            code = 2;
        }
        if(method.toLowerCase().equals("put")){
            code = 3;
        }
        if(method.toLowerCase().equals("delete")){
            code = 4;
        }
        return code;
    }
    // 获取请求接口函数
    private String getClassName(HandlerMethod handlerMethod){
        String methodName = handlerMethod.getMethod().getName();
        String className = handlerMethod.getMethod().getDeclaringClass().toString();
        className = className.replace("class ", "");
        String[] item = className.split("\\.");
        int len = item.length;
        return item[len-1] + "." + methodName;
    }

}
